package org.Shiikong_Memory.SakuraBlockFrame.CommandFramework;

import lombok.Setter;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import org.Shiikong_Memory.SakuraBlockFrame.Abnormal.NoRegisterCommand;
import org.Shiikong_Memory.SakuraBlockFrame.BasisTool.MessageTool;
import org.Shiikong_Memory.SakuraBlockFrame.ExternalAPI.PapiBuilder;
import org.bukkit.ChatColor;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 命令核心类，实现了 CommandExecutor 和 TabExecutor 接口，用于处理命令执行和命令补全逻辑。
 *
 * @author Shiikong_Memory
 * @version 1.0
 */
public class CommandCore implements CommandExecutor, TabExecutor {
    /**
     * 当玩家没有权限使用命令时显示的消息
     */
    @Setter
    private String NoPermissionMessage = ChatColor.RED +"你没有使用该指令的权限";
    /**
     * 当输入的命令不存在或格式错误时显示的消息
     */
    @Setter
    private String ErrorOrder = ChatColor.RED + "不存在该指令或格式错误";
    /**
     * 帮助信息每页显示的最大命令数量
     */
    @Setter
    private int maxHelpItem = 5;

    /**
     * Java 插件实例
     */
    private final JavaPlugin plugin;
    /**
     * 命令所需的权限
     */
    private final String permission;
    /**
     * 命令节点，用于构建命令树
     */
    private final CommandNode commandNode;

    /**
     * 记录命令路径和对应的命令节点
     *
     * @param path 命令路径
     * @param node 命令节点
     */
    public  record PathRecord(String path, CommandNode node) {}
    /**
     * 记录当前命令节点和其子节点的键列表
     *
     * @param currentNode 当前命令节点
     * @param childrenKeys 子节点的键列表
     */
    public record PathResult(CommandNode currentNode, List<String> childrenKeys) {}

    /**
     * 构造函数，初始化命令核心类
     *
     * @param plugin  Java 插件实例
     * @param Order   命令名称，会转换为小写
     * @param permission 命令所需的权限
     */
    public CommandCore(JavaPlugin plugin, String Order, String permission){
        Order = Order.toLowerCase();
        this.plugin = plugin;
        this.permission = permission;
        commandNode = new CommandNode();
        commandNode.name = "/"+Order;
        PluginCommand command = this.plugin.getCommand(Order);
        if (command == null)throw new NoRegisterCommand(Order+"命令");
        // 设置命令执行器为当前类实例
        command.setExecutor(this);

        addCommand(new Help());
    }

    /**
     * 批量添加命令监听器
     *
     * @param listener 命令监听器数组
     */
    public void addCommand(CommandListener... listener){
        for (CommandListener commandListener:listener){
            addCommand(commandListener);
        }
    }

    /**
     * 添加单个命令监听器
     *
     * @param listener 命令监听器
     */
    public void addCommand(CommandListener listener){
        // 遍历监听器类的所有声明方法
        for (Method method : listener.getClass().getDeclaredMethods()) {
            // 获取方法上的 SubCommand 注解
            SubCommand subCommand = method.getAnnotation(SubCommand.class);
            if (subCommand == null) continue;
            List<Arg> args = new ArrayList<>();
            // 解析方法参数
            Parameter[] parameters = method.getParameters();
            for (Parameter param : parameters) {
                // 获取参数上的 Arg 注解
                Arg arg = param.getAnnotation(Arg.class);
                if (arg != null) {
                    args.add(arg);
                }
            }
            DynamicTabCompleter completer = null;
            DynamicTab dynTab = method.getAnnotation(DynamicTab.class);
            if (dynTab != null) {
                try {
                    // 添加异常处理并检查构造函数
                    Constructor<?> constructor = dynTab.completer().getDeclaredConstructor();
                    constructor.setAccessible(true);
                    completer = (DynamicTabCompleter) constructor.newInstance();
                } catch (Exception e) {
                    plugin.getLogger().severe("动态补全器初始化失败: " + dynTab.completer().getName());
                    e.printStackTrace();
                }
            }
            // 获取方法上的所有 TabCompleteDef 注解
            List<TabCompleteDef> list = Arrays.stream(method.getAnnotationsByType(TabCompleteDef.class)).toList();
            // 构建命令节点
            CommandNode node = commandNode.addNodeByPath(subCommand.path(), args, list, dynTab==null?null:dynTab.param().toLowerCase(), completer);
            node.permission = subCommand.permission();
            node.description = subCommand.description();
            node.executor = method;
            node.handler = listener;
            node.args = args;

        }
    }

    /**
     * 命令执行方法，处理命令发送者发送的命令
     *
     * @param commandSender 命令发送者
     * @param command 命令对象
     * @param s 命令别名
     * @param strings 命令参数数组
     * @return 命令是否执行成功
     */
    @Override
    public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
        // 检查全局权限
        if (permission != null && !permission.isEmpty()){
            if (!commandSender.hasPermission(permission)){
                commandSender.sendMessage(NoPermissionMessage==null?"":NoPermissionMessage);
                return false;
            }
        }
        // 执行命令
        boolean isFinish  = commandNode.executeCommand(strings, commandSender);
        if (!isFinish){
            commandSender.sendMessage(ErrorOrder);
            return false;
        }
        return true;
    }

    /**
     * 命令补全方法，处理命令发送者输入命令时的补全建议
     *
     * @param sender 命令发送者
     * @param command 命令对象
     * @param alias 命令别名
     * @param strings 命令参数数组
     * @return 补全建议列表
     */
    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] strings) {
        // 检查全局权限
        if (permission != null && permission.isEmpty()){
            if (!sender.hasPermission(permission)){
                sender.sendMessage(NoPermissionMessage==null?"":NoPermissionMessage);
                return List.of();
            }
        }
        // 获取当前路径的子节点键列表
        PathResult pathResult = commandNode.getChildrenKeysByPath(strings);
        if (pathResult.currentNode() == null) return List.of();
        LinkedHashSet<String> list1 = new LinkedHashSet<>();
        // 过滤并处理补全建议
        List<String> list = pathResult.childrenKeys().stream()
                .filter(key -> {
                    CommandNode node = pathResult.currentNode().children.get(key);
                    if (!(node == null || node.permission == null
                            || node.permission.isEmpty()
                            || sender.hasPermission(node.permission)))return false;
                    if (isSpecialKey(key)){
                        DynamicTabCompleter completer = node.paramCompleters.get(key.toLowerCase());
                        if (completer != null) {
                            list1.addAll(completer.getCompletions(sender, strings));
                            return false;
                        }
                        if (!node.complementData.isEmpty()){
                            list1.addAll(node.complementData);
                        }else{
                            List<String> completions = node.argType.getCompletions();
                            list1.addAll(completions);
                            if (completions.isEmpty()){
                                if (node.argAlias.isEmpty()){
                                    return true;
                                }else{
                                    list1.add(node.argAlias);
                                    return false;
                                }
                            }
                        }
                        return false;
                    }
                    return true;
                })
                .toList();
        list1.addAll(list);
        // 添加 help 补全建议
        if (strings.length == 1){
            list1.add("help");
        }
        return list1.stream()
                .filter(s -> s.startsWith(strings[strings.length-1]))
                .toList();
    }

    /**
     * 发送命令帮助信息给命令发送者
     *
     * @param sender 命令发送者
     * @param page 帮助信息的页码
     */
    public void sendHelp(CommandSender sender, int page) {
        // 收集所有可用的命令
        List<PathRecord> allCommands = commandNode.collectAllPaths().stream()
                .filter(record -> record.node().permission == null
                        || record.node().permission.isEmpty()
                        || sender.hasPermission(record.node().permission))
                .toList();

        // 计算总页数
        int totalPages = (int) Math.ceil((double) allCommands.size() / maxHelpItem);
        page = Math.max(1, Math.min(page, totalPages));

        // 使用 MessageTool 构建消息
        MessageTool.Builder builder = MessageTool.builder()
                .addText("§6===== 命令帮助 (§e" + page + "§6/§e" + totalPages + "§6) =====");

        // 添加命令帮助信息
        allCommands.stream()
                .skip((page - 1) * (long) maxHelpItem)
                .limit(maxHelpItem)
                .forEach(cmd -> {
                    builder.addText("\n§7- §b" + cmd.path());
                    if (!cmd.node().description.isEmpty()) {
                        builder.addText(" §f» §7" + cmd.node().description);
                    }
                });

        // 添加分页按钮
        if (totalPages > 1) {
            builder.addText("\n\n");
            if (page > 1) {
                builder.addText("§a◀ 上一页")
                        .withClickEvent(ClickEvent.Action.RUN_COMMAND, commandNode.name + " help " + (page - 1))
                        .withHoverEvent(HoverEvent.Action.SHOW_TEXT, "点击查看上一页");
            }
            if (page < totalPages) {
                if (page > 1) builder.addText(" §7| ");
                builder.addText("§a下一页 ▶")
                        .withClickEvent(ClickEvent.Action.RUN_COMMAND, commandNode.name + " help " + (page + 1))
                        .withHoverEvent(HoverEvent.Action.SHOW_TEXT, "点击查看下一页");
            }
        }

        // 发送消息
        if (sender instanceof Player) {
            builder.build().sendTo((Player) sender);
        } else {
            // 控制台备用显示
            sender.sendMessage(ChatColor.stripColor(
                    builder.build().components.stream()
                            .map(c -> c.toLegacyText()) // 明确调用实例方法
                            .reduce("", (a, b) -> a + b)
            ));
        }
    }

    /**
     * 命令节点类，用于构建命令树
     */
    public class CommandNode{
        /**
         * 子命令名称
         */
        String name;
        /**
         * 子命令介绍
         */
        String description;
        /**
         * 子命令权限
         */
        String permission;
        /**
         * 触发方法
         */
        Method executor;
        /**
         * 调用方法的对象实例
         */
        Object handler;
        /**
         * 子节点映射
         */
        Map<String, CommandNode> children = new ConcurrentHashMap<>();
        /**
         * 参数注解列表
         */
        List<Arg> args = new ArrayList<>();
        /**
         * 参数类型
         */
        ArgType argType = ArgType.STRING;
        /**
         * 参数化名
         */
        String argAlias = "";
        /**
         * 注册的 Tab 补全参数
         */
        LinkedHashSet<String> complementData = new LinkedHashSet<>();
        /**
         * 动态补全方法
         */
        Map<String, DynamicTabCompleter> paramCompleters = new HashMap<>();
        /**
         * 根据路径获取下一层子节点
         *
         * @param path 命令路径数组
         * @return 包含当前命令节点和其子节点键列表的 PathResult 对象
         */
        public PathResult getChildrenKeysByPath(String[] path) {
            CommandNode currentNode = this;
            int size = path.length - 1;
            for (int i = 0; i< size; i++) {
                CommandNode currentNode1 = currentNode.children.get(path[i]);
                if (currentNode1 == null){
                     if (currentNode.children.isEmpty()) return new PathResult(null, List.of());
                     else {
                         currentNode1 = currentNode.children.values().iterator().next();
                     }
                }
                currentNode = currentNode1;
            }
            return new PathResult(currentNode, new ArrayList<>(currentNode.children.keySet()));
        }

        /**
         * 收集所有叶子节点路径
         *
         * @return 包含所有叶子节点路径记录的列表
         */
        public List<PathRecord> collectAllPaths() {
            List<PathRecord> results = new ArrayList<>();
            traversePaths(this, new ArrayList<>(), results, new AtomicInteger(0));
            return results;
        }

        /**
         * 递归遍历路径的核心方法
         *
         * @param node 当前命令节点
         * @param currentPath 当前路径列表
         * @param results 存储结果的列表
         */
        private void traversePaths(CommandNode node, List<String> currentPath, List<PathRecord> results, AtomicInteger argIndex) {
            // 处理节点名称
            String processedName = node.name;
            if (isSpecialKey(node.name)) {
                if (node.argAlias.isEmpty()){
                    processedName = node.name;
                }else{
                    processedName = node.argAlias;
                }
            }

            currentPath.add(processedName);

            if (node.children.isEmpty()) {
                String pathStr = String.join(" ", currentPath);
                results.add(new PathRecord(pathStr, node));
            } else {
                for (CommandNode child : node.children.values()) {
                    traversePaths(child, currentPath, results, argIndex);
                }
            }
            currentPath.remove(currentPath.size() - 1);
        }

        /**
         * 通过字符串路径添加节点
         *
         * @param path 命令路径字符串
         * @param args 参数注解列表
         * @param annotations Tab 补全定义注解列表
         * @return 最终添加的命令节点
         */
        public CommandNode addNodeByPath(String path, List<Arg> args, List<TabCompleteDef> annotations, String target, DynamicTabCompleter tabCompleter) {
            // 使用正则分割处理连续空格
            String[] keys = path.trim().split("\\s+");
            CommandNode currentNode = this;
            AtomicInteger integer = new AtomicInteger(0);
            for (String key : keys) {
                // 跳过空key（当有连续空格时会产生空字符串）
                if (key.isEmpty()) continue;
                currentNode = currentNode.children.computeIfAbsent(key,
                        k -> {
                            CommandNode newNode = new CommandNode();
                            newNode.name = k;
                            if(target != null){
                                if (newNode.name.equalsIgnoreCase(target) && tabCompleter != null) {
                                    newNode.paramCompleters.put(key, tabCompleter);
                                }
                            }
                            int i = integer.get();
                            annotations.stream()
                                    .filter(annotation -> k.equalsIgnoreCase(annotation.command()))
                                    .forEach(annotation -> {
                                        newNode.complementData.addAll(Arrays.asList(annotation.tab()));
                                    });
                            if (isSpecialKey(k)){
                                Arg arg = args.get(i);
                                newNode.argType = arg.type();
                                newNode.argAlias = arg.description();
                                integer.getAndIncrement();
                            }
                            return newNode;
                        });
            }
            return currentNode;
        }

        /**
         * 带参数解析的执行方法
         *
         * @param pathSegments 命令路径段数组
         * @param sender 命令发送者
         * @return 命令是否执行成功
         */
        public boolean executeCommand(String[] pathSegments, CommandSender sender) {
            CommandNode currentNode = this;
            List<String> collectedParams = new ArrayList<>();
            int segment = 0;
            while(!currentNode.children.isEmpty()){
                // 先尝试精确匹配子节点
                CommandNode next;
                next = pathSegments.length>segment?currentNode.children.get(pathSegments[segment]):null;
                if (next != null) {
                    currentNode = next;
                    segment++;
                    continue;
                }else {
                    // 查找参数节点（优化后的单次查找）
                    CommandNode paramNode = currentNode.children.values().stream()
                            .filter(node -> {
                                return isSpecialKey(node.name);
                            })
                            .findFirst()
                            .orElse(null);
                    if (pathSegments.length>segment){
                        collectedParams.add(pathSegments[segment]);
                    }else{
                        collectedParams.add(null);
                    }
                    if (paramNode == null) {
                        break;
                    }
                    currentNode = paramNode;
                    segment++;
                }

            }
            if (currentNode.permission != null && !currentNode.permission.isEmpty()){
                if (!sender.hasPermission(currentNode.permission)){
                    sender.sendMessage(NoPermissionMessage);
                    return true; // 特殊返回，玩家权限不足
                }
            }
            if (currentNode.executor == null) {
                return false;
            }

            // 参数解析逻辑
            try {
                Parameter[] parameters = currentNode.executor.getParameters();
                Object[] args = new Object[parameters.length];

                int paramIndex = 0;
                for (int i = 0; i < parameters.length; i++) {
                    if (parameters[i].getType().isAssignableFrom(CommandSender.class)) {
                        args[i] = sender;
                    }else if (parameters[i].getType().isAssignableFrom(Player.class)){
                        if (sender instanceof Player){
                            args[i] = (Player) sender;
                        }
                    } else if (parameters[i].isAnnotationPresent(Arg.class)) {
                        Arg arg = parameters[i].getAnnotation(Arg.class);
                        if (paramIndex < collectedParams.size()) {
                            if (ArgType.Auto.equals(arg.type())){
                                args[i] = ArgumentConverter.convert(collectedParams.get(paramIndex), parameters[i].getType());
                            }else{
                                args[i] = ArgumentConverter.convert(collectedParams.get(paramIndex), arg.type().getType());
                            }
                            paramIndex++;
                        } else if (arg.options()) {
                            args[i] = ArgumentConverter.getDefaultValue(parameters[i].getType());
                        } else {
                            return false; // 必需参数缺失
                        }
                    }
                }
                currentNode.executor.invoke(currentNode.handler, args);
                return true;
            }catch (NumberFormatException e){
                return false;
            } catch (Exception e) {
                throw new RuntimeException("指令在执行时发生了错误", e);
            }
        }
    }

    /**
     * 判断给定的键是否为特殊键
     * 特殊键以 < 开头并以 > 结尾，或者以 [ 开头并以 ] 结尾
     *
     * @param key 要判断的键
     * @return 如果是特殊键返回 true，否则返回 false
     */
    private boolean isSpecialKey(String key) {
        return (key.startsWith("<") && key.endsWith(">")) || (key.startsWith("[") && key.endsWith("]"));
    }

    private class Help implements CommandListener{
        @SubCommand(path = "help <pages>", permission = "", description="命令帮助文档")
        public void onHelp(
                CommandSender sender,
                @Arg(description = "<页数>", options = true) Integer pages
        ) {
            sendHelp(sender, pages == null ? 1 : pages);
        }

        @SubCommand(path = "papi help <page>", description = "PAPI占位符帮助文档")
        public void onPapiHelp(
                CommandSender sender,
                @Arg(description = "<页码>", options = true) Integer page
        ) {
            PapiBuilder.sendHelp(sender, page == null ? 1 : page);
        }
    }
}
